package com.zzyl.nursing.service.impl;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.nursing.config.WebSocketServer;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.vo.AlertNotifyVo;
import com.zzyl.system.mapper.SysUserRoleMapper;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertDataMapper;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.service.IAlertDataService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

/**
 * 报警数据Service业务层处理
 * 
 * @author szc
 * @date 2025-08-26
 */
@Service
public class AlertDataServiceImpl extends ServiceImpl<AlertDataMapper, AlertData> implements IAlertDataService
{
    @Autowired
    private AlertDataMapper alertDataMapper;

    @Autowired
    private AlertRuleMapper alertRuleMapper;

    @Autowired
    private RedisTemplate  redisTemplate;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private WebSocketServer webSocketServer;

    /**
     * 查询报警数据
     * 
     * @param id 报警数据主键
     * @return 报警数据
     */
    @Override
    public AlertData selectAlertDataById(Long id)
    {
        return alertDataMapper.selectById(id);
    }

    /**
     * 查询报警数据列表
     * 
     * @param alertData 报警数据
     * @return 报警数据
     */
    @Override
    public List<AlertData> selectAlertDataList(AlertData alertData)
    {
        return alertDataMapper.selectAlertDataList(alertData);
    }

    /**
     * 新增报警数据
     * 
     * @param alertData 报警数据
     * @return 结果
     */
    @Override
    public int insertAlertData(AlertData alertData)
    {
        return alertDataMapper.insert(alertData);
    }

    /**
     * 修改报警数据
     * 
     * @param alertData 报警数据
     * @return 结果
     */
    @Override
    public int updateAlertData(AlertData alertData)
    {
        return alertDataMapper.updateById(alertData);
    }

    /**
     * 批量删除报警数据
     * 
     * @param ids 需要删除的报警数据主键
     * @return 结果
     */
    @Override
    public int deleteAlertDataByIds(Long[] ids)
    {
        return alertDataMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除报警数据信息
     * 
     * @param id 报警数据主键
     * @return 结果
     */
    @Override
    public int deleteAlertDataById(Long id)
    {
        return alertDataMapper.deleteById(id);
    }

    /**
     * 报警数据处理
     */
    @Override
    public void alertDataProcess() {
        // 1.统计是否有规则
        Long count = alertRuleMapper.selectCount(new LambdaUpdateWrapper<AlertRule>().eq(AlertRule::getStatus, 1));
        if (count<=0L){
            return;
        }
        // 2.从Redis中获取上报数据
        // 取出所有的值，类型是List<Object>，但每个Object实际上是List<DeviceData>
        List<Object> objectList = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_LAST_DATA);
        // 3.是否有数据
        if (CollectionUtil.isEmpty(objectList)){
            return;
        }
        List<List<DeviceData>> allDeviceData = new ArrayList<>();
        for (Object obj : objectList) {
            if (obj instanceof List) {
                allDeviceData.add((List<DeviceData>) obj);
            }
        }

        // 4.规则和数据匹配
        allDeviceData.forEach(eachList -> eachList.forEach(
                deviceData -> {
                    //是否超时一分钟
                    if (deviceData.getAlarmTime().plusMinutes(1).isAfter(LocalDateTime.now())){
                        matchAlertRule(deviceData);
                    }
                }
        ));
    }

    /**
     * 设备的规则匹配
     * @param deviceData
     */
    public void matchAlertRule(DeviceData deviceData) {
        LambdaQueryWrapper<AlertRule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AlertRule::getStatus, 1)
                .in(AlertRule::getIotId, -1,deviceData.getIotId())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId());
        List<AlertRule> alertRules = alertRuleMapper.selectList(queryWrapper);
        if (CollectionUtil.isEmpty(alertRules)){
            return;
        }
        //遍历每一条规则
        alertRules.forEach(alertRule -> {
            //是否触发规则报警
            isMatchAlertRule(alertRule, deviceData);
        });
    }

    /**
     * 是否触发规则报警
     * @param alertRule
     * @param deviceData
     */
    public void isMatchAlertRule(AlertRule alertRule, DeviceData deviceData) {
        //Redis报警沉默周期,报警次数唯一key
        String silentKey=CacheConstants.ALERT_SILENT_PREFIX+alertRule.getIotId()+"_"+deviceData.getIotId()+"_"+alertRule.getId();
        String triggerCountKey=CacheConstants.ALERT_TRIGGER_COUNT_PREFIX+alertRule.getIotId()+"_"+deviceData.getIotId()+"_"+alertRule.getId();
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime startTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        LocalTime localTime = deviceData.getAlarmTime().toLocalTime();
        //是否在生效时间内
        if (localTime.isAfter(startTime) && localTime.isBefore(endTime)){
            //数据是否达到阈值
            String operator = alertRule.getOperator();
            Double value = Double.valueOf(deviceData.getDataValue().toString());
            Double ruleValue = alertRule.getValue();
            if ((">=".equals(operator)&&Double.compare(value,ruleValue)>=0)
            || ("<".equals(operator)&&Double.compare(value,ruleValue)<0)){
                //redis查询报警沉默周期
                if (Objects.isNull(redisTemplate.opsForValue().get(silentKey))) {
                    //查询已报警次数
                    Integer redisCount = (Integer) redisTemplate.opsForValue().get(triggerCountKey);
                    redisCount = redisCount==null?1:redisCount+1;
                    if (redisCount.equals(alertRule.getDuration())){
                        //删除Redis报警次数
                        redisTemplate.delete(triggerCountKey);
                        //添加Redis沉默周期
                        redisTemplate.opsForValue().set(silentKey,1,alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);
                        //插入报警数据
                        selfInsertBatch(alertRule,deviceData);
                    }else {
                        redisTemplate.opsForValue().set(triggerCountKey,redisCount);
                    }
                }
            }else {
                //没达到阈值，清除缓存报警次数
                redisTemplate.delete(triggerCountKey);
            }
        }
    }
    //插入报警数据
    public void selfInsertBatch(AlertRule alertRule, DeviceData deviceData) {
        List<Long> userIds=new ArrayList<>();
        //是否是老人数据
        if (alertRule.getAlertDataType().equals(0)){
            //是否是固定设备
            if (deviceData.getLocationType().equals(1)){
                userIds=deviceMapper.selectNursingIdsByIotIdWithBed(deviceData.getIotId());
            }else {
                userIds=deviceMapper.selectNursingIdsByIotIdWithElder(deviceData.getIotId());
            }
        }else {
            userIds = sysUserRoleMapper.selectUserIdsByRoleName("维修工");
        }
        userIds.addAll(sysUserRoleMapper.selectUserIdsByRoleName("超级管理员"));
        List<AlertData> alertDataList = userIds.stream().map(userId -> {
            AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
            String alertReason = StrUtil
                    .format("{}{}{},持续{}个周期就报警", alertRule.getFunctionName(), alertRule.getOperator(), alertRule.getValue(), alertRule.getDuration());
            alertData.setAlertReason(alertReason);
            alertData.setId(null);
            alertData.setUserId(userId);
            alertData.setAlertRuleId(alertRule.getId());
            alertData.setType(alertRule.getAlertDataType());
            alertData.setStatus(0);
            return alertData;
        }).collect(Collectors.toList());
        saveBatch(alertDataList);

        //websocket推送报警信息给用户
        webSocketNotify(alertDataList.get(0),alertRule,userIds);
    }

    /**
     * websocket推送报警信息给用户
     * @param alertData
     * @param alertRule
     * @param userIds
     */
    public void webSocketNotify(AlertData alertData, AlertRule alertRule, List<Long> userIds) {
        AlertNotifyVo notifyVo = BeanUtil.toBean(alertData, AlertNotifyVo.class);
        notifyVo.setFunctionName(alertRule.getFunctionName());
        notifyVo.setAlertDataType(alertRule.getAlertDataType());
        notifyVo.setVoiceNotifyStatus(0);
        notifyVo.setNotifyType(1);
        notifyVo.setIsAllConsumer(alertData.getLocationType() == 1 && alertData.getPhysicalLocationType() == 2);
        webSocketServer.sendMessageToConsumer(notifyVo, userIds);
    }
}
